/*******************************************************************************
 * Copyright (c) 2010 L.Carbonnaux.
 *******************************************************************************/

package org.lcx.taskvision.ui.wizzard;

import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.mylyn.tasks.core.TaskRepository;
import org.eclipse.mylyn.tasks.ui.wizards.AbstractRepositorySettingsPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.List;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.events.ExpansionAdapter;
import org.eclipse.ui.forms.events.ExpansionEvent;
import org.eclipse.ui.forms.widgets.ExpandableComposite;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Section;
import org.eclipse.ui.progress.IProgressService;
import org.lcx.taskvision.core.ITaskVisionClient;
import org.lcx.taskvision.core.ITaskVisionConstants;
import org.lcx.taskvision.core.TaskVisionCorePlugin;
import org.lcx.taskvision.ui.TaskVisionUiTools;

/**
 * @author Laurent Carbonnaux
 */
public class TaskVisionRepositorySettingsPage extends
		AbstractRepositorySettingsPage {

	private ExpandableComposite selectionExpComposite;
	
	private Composite selectionComposite;

	private Composite spreadsheetcomposite;
	
	private List spreadsheets;
	private List taskWorksheets;
	
	private Button updateButton;
	private Button refreshButton;
	
	private TaskRepository docListRepository;

	private static final String TITLE = Messages.ScrumVisionRepositorySettingsPage_title;

	private static final String DESCRIPTION = Messages.ScrumVisionRepositorySettingsPage_finish_the_settings;

	private final FormToolkit toolkit = new FormToolkit(Display.getCurrent());
	
	private String spreadsheetName;
	private Map<String, String> taskCellFeedUrl = new HashMap<String, String>();
	private Map<String, String> taskListFeedUrl = new HashMap<String, String>();
	private Map<String, String> taskWorksheetLabel = new HashMap<String, String>();
	
	public TaskVisionRepositorySettingsPage(TaskRepository taskRepository) {
		super(TITLE, DESCRIPTION, taskRepository);
		setNeedsAnonymousLogin(false);
		setNeedsValidation(false);

		setNeedsEncoding(false);
		docListRepository = new TaskRepository(TaskVisionCorePlugin.CONNECTOR_KIND, 
				TaskVisionCorePlugin.getSpreadsheetsFeedUrl());
	}

	@Override
	public boolean isPageComplete() {
		String errorMessage = null;
		String url = this.getRepositoryUrl();
		errorMessage = isUniqueUrl(url);
		if (errorMessage == null) {
			errorMessage = isCredentialsComplete();
		}
		if (errorMessage == null && !isValidUrl(url)) {
			errorMessage = Messages.ScrumVisionRepositorySettingsPage_backlog_not_choosen;
		}
		setErrorMessage(errorMessage);
		return errorMessage == null;

	}
	
	private String isCredentialsComplete() {
		if (repositoryUserNameEditor.getStringValue().trim().equals("") || (repositoryPasswordEditor.getStringValue()
						.trim().equals(""))) {
			if(updateButton!=null) updateButton.setEnabled(false);
			return Messages.ScrumVisionRepositorySettingsPage_valid_credential;
		} else {
			if(updateButton!=null) updateButton.setEnabled(true);
		}
		return null;

	}

	@Override
	protected Validator getValidator(TaskRepository repository) {
		return null;
	}
	
	@Override
	protected boolean isValidUrl(String name) {
		if (name.startsWith(URL_PREFIX_HTTP) && !name.endsWith("/") && 
				!name.contains("_SPREADSHEET_") && !name.contains("_WORKSHEET_") ) {
			try {
				new URL(name);
				return true;
			} catch (MalformedURLException e) {
			}
		}
		return false;
	}
	

	@Override
	protected void createAdditionalControls(Composite parent) {
		
		serverUrlCombo.setEnabled(false);
		
		repositoryUserNameEditor.setFocus();
	
		Composite expComp = parent.getParent();
		if(expComp instanceof ExpandableComposite){
			((ExpandableComposite)expComp).setExpanded(true);
		}
		
		this.createSelectionComposite(parent);
		this.createSelectSpreadSheetGroup(selectionComposite);
		
	}
	
	/**
	 * Create the "select backlog" composite
	 * @param parent
	 */
	private void createSelectionComposite(Composite parent) {
		selectionExpComposite = toolkit.createExpandableComposite(parent, Section.COMPACT
				| Section.TWISTIE | Section.TITLE_BAR);
		selectionExpComposite.clientVerticalSpacing = 0;
		GridData gridData_3 = new GridData(SWT.FILL, SWT.FILL, true, false);
		gridData_3.horizontalIndent = -5;
		selectionExpComposite.setLayoutData(gridData_3);
		selectionExpComposite.setFont(compositeContainer.getFont());
		selectionExpComposite.setBackground(compositeContainer.getBackground());
		selectionExpComposite.setText(Messages.ScrumVisionRepositorySettingsPage_choose_backlog);
		selectionExpComposite.addExpansionListener(new ExpansionAdapter() {
			@Override
			public void expansionStateChanged(ExpansionEvent e) {
				getControl().getShell().pack();
			}
		});

		GridDataFactory.fillDefaults().grab(true, false).span(2, SWT.DEFAULT).applyTo(selectionExpComposite);

		selectionComposite = toolkit.createComposite(selectionExpComposite, SWT.NONE);
		GridLayout gridLayout3 = new GridLayout();
		gridLayout3.numColumns = 2;
		gridLayout3.verticalSpacing = 5;
		selectionComposite.setLayout(gridLayout3);
		selectionComposite.setBackground(compositeContainer.getBackground());
		selectionExpComposite.setClient(selectionComposite);
	}

	private void createSelectSpreadSheetGroup(Composite parent){

		spreadsheetcomposite = new Composite(parent, SWT.NONE);
		spreadsheetcomposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 2, 1));
		final GridLayout gridLayout = new GridLayout();
		gridLayout.marginBottom = 0;
		gridLayout.marginHeight = 0;
		gridLayout.marginWidth = 0;
		gridLayout.numColumns = 2;
		spreadsheetcomposite.setLayout(gridLayout);
		
		createSpreadSheetGroup(spreadsheetcomposite);
		createWorkSheetGroupTask(spreadsheetcomposite);
		
		displayBacklogInformation();

		updateButton = new Button(parent, SWT.PUSH);
		updateButton.setText(Messages.ScrumVisionRepositorySettingsPage_update_button);
		updateButton.setToolTipText(Messages.ScrumVisionRepositorySettingsPage_update_button_tooltip);
		updateButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
		updateButton.setEnabled(false);
		updateButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
					initSpreadSheetList();
			}
		});
		if(repository!=null) {
			updateButton.setVisible(false);
		}
		
		// refresh button display
		refreshButton = new Button(parent, SWT.PUSH);
		refreshButton.setText(Messages.ScrumVisionRepositorySettingsPage_refresh_button);
		refreshButton.setToolTipText(Messages.ScrumVisionRepositorySettingsPage_refresh_button_tooltip);
		refreshButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
		refreshButton.setEnabled(true);
		refreshButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				initSpreadSheetList();
				initWorkSheetList(spreadsheetName);
				displayBacklogInformation();
			}
		});
		
		if(repository==null) {
			refreshButton.setVisible(false);
		}
		
	}
	
	private void createSpreadSheetGroup(Composite parent){

		final Label spreadSheetLabel = new Label(parent, SWT.NONE);
		spreadSheetLabel.setText(Messages.ScrumVisionRepositorySettingsPage_backlog_spreadsheet);

		spreadsheets = new List(parent, SWT.SINGLE | SWT.V_SCROLL | SWT.BORDER);
		spreadsheets.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
		spreadsheets.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				if (spreadsheets.getSelectionIndex() != -1) {
					spreadsheetName = spreadsheets.getItem(spreadsheets.getSelectionIndex());
					initWorkSheetList(spreadsheetName);
					
				} else {
					spreadsheetName=null;
					initSpreadSheetList();
				}
				serverUrlCombo.setText("");
				repositoryLabelEditor.setStringValue("");
				isPageComplete();
				if (getWizard() != null) {
					getWizard().getContainer().updateButtons();
				}
			}
		});
		
	}

	private void createWorkSheetGroupTask(Composite parent){

		final Label workSheetLabel = new Label(parent, SWT.NONE);
		workSheetLabel.setText(Messages.ScrumVisionRepositorySettingsPage_task_worksheet);

		taskWorksheets = new List(parent, SWT.SINGLE | SWT.V_SCROLL | SWT.BORDER);
		taskWorksheets.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
		taskWorksheets.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				if (taskWorksheets.getSelectionIndex() != -1) {
					String workSheetName = taskWorksheets.getItem(taskWorksheets.getSelectionIndex());
					if(spreadsheets.getSelectionIndex() != -1){
						spreadsheetName = spreadsheets.getItem(spreadsheets.getSelectionIndex());
						taskCellFeedUrl.put(workSheetName, TaskVisionUiTools.getCellFeedURL(docListRepository.getUrl(), spreadsheetName, workSheetName));
						taskListFeedUrl.put(workSheetName, TaskVisionUiTools.getListFeedURL(docListRepository.getUrl(), spreadsheetName, workSheetName));
						taskWorksheetLabel.put(workSheetName, workSheetName);
						serverUrlCombo.setText(TaskVisionUiTools.getListFeedURL(docListRepository.getUrl(), spreadsheetName, workSheetName));
						repositoryLabelEditor.setStringValue(spreadsheetName+ " - " + workSheetName);
					}
				} else {
					taskCellFeedUrl.clear();
					taskListFeedUrl.clear();
					taskWorksheetLabel.clear();
				}
				isPageComplete();
				if (getWizard() != null) {
					getWizard().getContainer().updateButtons();
				}
			}
		});
	}
	
	private void initSpreadSheetList() {

		applyTo(docListRepository);

		IRunnableWithProgress updateRunnable = new IRunnableWithProgress() {
			public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
				if (monitor == null) {
					monitor = new NullProgressMonitor();
				}
				try {
					monitor.beginTask(Messages.ScrumVisionQueryWizzard_updating_repository, IProgressMonitor.UNKNOWN);
					TaskVisionUiTools.updateSpreadSheetList(docListRepository, monitor);
				} catch (final Exception e) {
					e.printStackTrace();
					throw new InvocationTargetException(e);
				} finally {
					monitor.done();
				}
			}
		};

		if (runUpdate(updateRunnable)) return;
		
		spreadsheets.setItems(TaskVisionUiTools.getSpreadSheetOptions(ITaskVisionConstants.PREF_SPREADSHEET_NAME, docListRepository.getUrl()));
		taskWorksheets.removeAll();
		
	}

	private void initWorkSheetList(String spreadSheetName) {
		String[] ws = TaskVisionUiTools.getWorkSheetOptions(ITaskVisionConstants.PREF_WORKSHEET_NAME, docListRepository.getUrl(), spreadSheetName);
		taskWorksheets.removeAll();
		for (int i = 0; i < ws.length; i++) {
			taskWorksheets.add(ws[i]);
		}
	}
	
	private boolean runUpdate(IRunnableWithProgress updateRunnable) {
		try {
			if (getContainer() != null) {
				getContainer().run(true, true, updateRunnable);
			} else {
				IProgressService service = PlatformUI.getWorkbench().getProgressService();
				service.busyCursorWhile(updateRunnable);
			}

		} catch (Exception e) {
			displayError(getRepositoryUrl(), e);
			return true;
		}
		return false;
	}
	
	private void displayError(final String serverUrl, Exception e) {
		String errorMessage=null;
		if (e instanceof MalformedURLException) {
			errorMessage = Messages.ScrumVisionRepositorySettingsPage_url_invalid_Error;
		} else {
			errorMessage = Messages.ScrumVisionRepositorySettingsPage_Error;
		}
		setErrorMessage(errorMessage);
		if (e instanceof InvocationTargetException) {
			TaskVisionCorePlugin.logError(e.getCause());
		} else {
			TaskVisionCorePlugin.logError(e);
		}
	}
	

	@Override
	public String getConnectorKind() {
		return TaskVisionCorePlugin.CONNECTOR_KIND;
	}

	/**
	 * Method called after Finish, repository exists
	 */
	@Override
	public void applyTo(TaskRepository repository) {
		super.applyTo(repository);
		//if page is completed creates repositories for other selected worksheets
		if(isPageComplete()) {
			createOtherRepositories(repository);
		}
	}

	private void displayBacklogInformation () {
		// display data for existing repository and disable selection
		if(repository!=null) {
			selectionExpComposite.setExpanded(true);
			spreadsheets.removeAll();
			spreadsheetName = repository.getProperty(ITaskVisionClient.PROPERTY_SPREADSHEET_NAME);
			spreadsheets.add(spreadsheetName);
			spreadsheets.select(0);
			spreadsheets.setEnabled(false);
			
			taskListFeedUrl.clear();
			taskCellFeedUrl.clear();
			taskWorksheetLabel.clear();

			SortedSet<String> sortedKeys = new TreeSet<String>();
			for(String key : repository.getProperties().keySet()) {
				if(key.startsWith(ITaskVisionClient.PROPERTY_TASK_LIST_FEED_URL)) {
					String ws = key.substring(ITaskVisionClient.PROPERTY_TASK_LIST_FEED_URL.length());
					taskListFeedUrl.put(ws, repository.getProperty(key));
					sortedKeys.add(ws);
				} else if(key.startsWith(ITaskVisionClient.PROPERTY_TASK_CELL_FEED_URL)) {
					String ws = key.substring(ITaskVisionClient.PROPERTY_TASK_CELL_FEED_URL.length());
					taskCellFeedUrl.put(ws, repository.getProperty(key));
				} else if(key.startsWith(ITaskVisionClient.PROPERTY_TASK_WORKSHEET_LABEL)) {
					String ws = key.substring(ITaskVisionClient.PROPERTY_TASK_WORKSHEET_LABEL.length());
					taskWorksheetLabel.put(ws, repository.getProperty(key));
				}
			}
			if(taskWorksheets.getItemCount()==0) {
				int i = 0;
				for (Iterator<String> iterator = sortedKeys.iterator(); iterator.hasNext();i++) {
					String key = (String) iterator.next();
					taskWorksheets.add(key);
					if (taskListFeedUrl.get(key).equals(repository.getUrl())){
						taskWorksheets.select(i);	
					}
				}
			}
		}
		
	}
	
	private void createOtherRepositories(TaskRepository repository) {
		if(repository==null) return;
		//TODO : should thing about cleaning the properties first!
		if(taskListFeedUrl!=null){
			repository.setProperty(ITaskVisionClient.PROPERTY_SPREADSHEET_NAME, spreadsheetName);
			for (String wsName : taskListFeedUrl.keySet()) {
				repository.setProperty(ITaskVisionClient.PROPERTY_TASK_LIST_FEED_URL, taskListFeedUrl.get(wsName));
			}
			for (String wsName : taskCellFeedUrl.keySet()) {
				repository.setProperty(ITaskVisionClient.PROPERTY_TASK_CELL_FEED_URL, taskCellFeedUrl.get(wsName));
				
			}
			for (String wsName : taskWorksheetLabel.keySet()) {
				repository.setProperty(ITaskVisionClient.PROPERTY_TASK_WORKSHEET_LABEL, taskWorksheetLabel.get(wsName));
			}
			
		}
	}
	
}
